package com.alibaba.nacos.client.naming.event;

import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName InstancesChangeNotifier
 * @Description: TODO
 * @Author linjiahao
 * @Date 2023/2/1
 **/
public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
    private final Map<String, ConcurrentHashSet<EventListener>> listenerMap = new ConcurrentHashMap();
    private final Object lock = new Object();

    public InstancesChangeNotifier() {
    }

    public void registerListener(String serviceName, String clusters, EventListener listener) {
        String key = ServiceInfo.getKey(serviceName, clusters);
        ConcurrentHashSet<EventListener> eventListeners = (ConcurrentHashSet)this.listenerMap.get(key);
        if (eventListeners == null) {
            synchronized(this.lock) {
                eventListeners = (ConcurrentHashSet)this.listenerMap.get(key);
                if (eventListeners == null) {
                    eventListeners = new ConcurrentHashSet();
                    this.listenerMap.put(key, eventListeners);
                }
            }
        }

        eventListeners.add(listener);
    }

    public void deregisterListener(String serviceName, String clusters, EventListener listener) {
        String key = ServiceInfo.getKey(serviceName, clusters);
        ConcurrentHashSet<EventListener> eventListeners = (ConcurrentHashSet)this.listenerMap.get(key);
        if (eventListeners != null) {
            eventListeners.remove(listener);
            if (CollectionUtils.isEmpty(eventListeners)) {
                this.listenerMap.remove(key);
            }

        }
    }

    public boolean isSubscribed(String serviceName, String clusters) {
        String key = ServiceInfo.getKey(serviceName, clusters);
        ConcurrentHashSet<EventListener> eventListeners = (ConcurrentHashSet)this.listenerMap.get(key);
        return CollectionUtils.isNotEmpty(eventListeners);
    }

    public List<ServiceInfo> getSubscribeServices() {
        List<ServiceInfo> serviceInfos = new ArrayList();
        Iterator var2 = this.listenerMap.keySet().iterator();

        while(var2.hasNext()) {
            String key = (String)var2.next();
            serviceInfos.add(ServiceInfo.fromKey(key));
        }

        return serviceInfos;
    }

    @Override
    public void onEvent(InstancesChangeEvent event) {
        String key = ServiceInfo.getKey(event.getServiceName(), event.getClusters());
        ConcurrentHashSet<EventListener> eventListeners = (ConcurrentHashSet)this.listenerMap.get(key);
        if (!CollectionUtils.isEmpty(eventListeners)) {
            Iterator var4 = eventListeners.iterator();

            while(true) {
                while(var4.hasNext()) {
                    final EventListener listener = (EventListener)var4.next();
                    final Event namingEvent = this.transferToNamingEvent(event);
                    if (listener instanceof AbstractEventListener && ((AbstractEventListener)listener).getExecutor() != null) {
                        ((AbstractEventListener)listener).getExecutor().execute(new Runnable() {
                            @Override
                            public void run() {
                                listener.onEvent(namingEvent);
                            }
                        });
                    } else {
                        listener.onEvent(namingEvent);
                    }
                }

                return;
            }
        }
    }

    private Event transferToNamingEvent(InstancesChangeEvent instancesChangeEvent) {
        return new NamingEvent(instancesChangeEvent.getServiceName(), instancesChangeEvent.getGroupName(), instancesChangeEvent.getClusters(),
                instancesChangeEvent.getHosts(),instancesChangeEvent.getEventType());
    }

    @Override
    public Class<? extends com.alibaba.nacos.common.notify.Event> subscribeType() {
        return InstancesChangeEvent.class;
    }
}
